查看原文
其他

【周末AI课堂】神经网络综观(代码篇)| 机器学习你会遇到的“坑”

唐僧不用海飞丝 读芯术 2019-12-26


AI课堂开讲,就差你了!


很多人说,看了再多的文章,可是没有人手把手地教授,还是很难真正地入门AI。为了将AI知识体系以最简单的方式呈现给你,从这个星期开始,芯君邀请AI专业人士开设“周末学习课堂”——每周就AI学习中的一个重点问题进行深度分析,课程会分为理论篇和代码篇,理论与实操,一个都不能少!


来,退出让你废寝忘食的游戏页面,取消只有胡吃海塞的周末聚会吧。未来你与同龄人的差异,也许就从每周末的这堂AI课开启了!


读芯术读者交流群,请加小编微信号:zhizhizhuji。等你。后台回复“周末AI课堂”,查阅相关源代码。

全文共2245字,预计学习时长5分钟




在前面的《神经网络综观(理论篇)》中,我们到目前已经对神经网络的设计有了具体的了解,主要基于获得更好的表示和更好的优化,从宏观上,层与层的连接方式,每层神经元的数量,层的类别和个数,以及如何将不同种类的层组合起来,微观上则包含了隐层神经元和输出单元的种类。对神经网络的设计要考虑具体面对的问题,比如面对我们在前面课程中反复使用的iris分类数据,一个普通的全连接网络就可以解决,如果解决图片识别的问题,那么带有卷积层的神经网络可能会适应的更好,如果面对语音识别,一个双向添加LSTM结构的循环神经网络可能是必要的,但无一例外,在具体实践中,我们需要根据理论对上述的组件进行更新。


我们前面曾经使用numpy自行搭建了一个简单的感知机:

class NeuralNetwork:

    def__init__(self, x, y):
       self.input      = x 
       self.weights   = np.random.rand(x.shape[
1],1)
       self.weights1   = np.random.rand(
1)
       self.y          = y
       self.output     = np.zeros(self.y.shape)
    
def feedforward(self):
       self.output = sigmoid(np.dot(self.input, self.weights)+self.weights1)
    
def backprop(self):
       d_weights = np.dot(self.input.T,(
2*(self.y -self.output) * sigmoid_derivative(self.output)))
       d_weights1 =np.dot(
2*(self.y -self.output).reshape(4),sigmoid_derivative(self.output).reshape(4))
       self.weights += d_weights
       self.weights1 += d_weights1


如果将隐层的数目和神经元的拓展是非常容易的,我们在初始化的时候可以很方便的添加:

......

self.weights2   = np.random.rand(10,1)     
......


这样就获得了一个10个神经元的隐层。


但如果涉及到更大型更深的网络,这样的拓展就不再容易,所以我们必须掌握专门用于深度学习的框架,让我们快速的搭建模型并检验效果。所以在这里,我推荐使用keras来作为深度学习的入门工具,目前深度学习的框架非常之多,比如tensorflow,caffe,CNTK,torch,theano,paddlepaddle,mxnet等等,但keras搭建模型的速度非常快,这意味着创新性的想法可以被很快的实现,同时具有一定的灵活性,运行速度也不慢,也可以很方便在GPU上运行,最重要的是,在掌握理论的基础上,学习keras就像迈出左脚再迈右脚一样自然。


图为在google各个深度学习框架的搜索次数,一定程度上可以反映出用户对深度学习框架的感兴趣程度,可以看到keras增长迅猛,仅次于tensorflow。


在统计学习中,虽然经常使用sklearn,但我并未做简单介绍,因为统计学习更强调的是数学和模型,sklearn包含的内容太多,一个严重的后果是使得一部分读者还没有入门就已经放弃,所以在开始使用keras做任务之前,本文的主要目的就是向大家介绍神经网络在keras中的体现,以及keras的简单使用,你大概只需要花几分钟的时间就可以上手它。


首先,一个神经网络必须有输入输出,在keras中,我们要先定义好一个模型:

from keras.models import Model

from keras.layers import Input
inputs=Input(shape=(
100,))
model=Model(inputs=inputs,outputs=inputs)


我们创建了一个输入有100维的神经元模型,但注意到我们的输入和输出都是一样的,这意味着我们只是创建了一个没有任何用处的100个神经元,放在inputs层里。keras.layers类中提供了很多种层,我们接下来添加全连接层,只需要:

from keras.models import Model

from keras.layers import Input,Dense
inputs=Input(shape=(
100,))
x=Dense(
32)(inputs)
model=Model(inputs=inputs,outputs=x)


全连接的意思是,前一层所有的神经元与后一层的神经元均存在权重连接。接下来,我们需要激活函数,需要激活函数来调整神经网络,我们使用了ReLU作为激活函数提取出来,让其单独成为一层。并添加到原来的模型中:

from keras.models import Model

from keras.layers import Input,Dense,ReLU
inputs=Input(shape=(
100,))
x=Dense(
32)(inputs)
y=ReLU()(x)
model=Model(inputs=inputs,outputs=y)


通过这样的添加,我们已经获得了一个两层的神经网络,输出的值就为激活函数的处理之后的输出,准确的说,这只是一个输入为100维,输出为32维的感知机,我们要继续添层加使其能够处理非线性问题,紧接着,我们添加一个用于输出的层,并采用softmax函数作为激活函数,添加到上述模型中:

from keras.models import Model

from keras.layers import Input,Dense,ReLU,softmax
inputs=Input(shape=(
100,))
x=Dense(
32)(inputs)
y=ReLU()(x)
out=Dense(
10)(y)
out=softmax()(out)
model=Model(inputs=inputs,outputs=out)


我们最终的模型就是处理100维特征的10分类数据。需要注意的是,隐藏单元和输出单元功能并不一样,输出单元一般都可以作为隐藏单元,但隐藏单元只有少数几种可以成为输出单元,这与我们使用的损失函数有关。为了达到同样的效果,激活函数可以在层内事先指定好,比如:

x=Dense(32)(inputs)

y=ReLU()(x)


还可以把激活函数和层放在一起写作:

y=Dense(32,activation='relu')(inputs)


两种方法没有什么特别的区别。模型搭建完成后,我们完成了表示的任务,我们在开始优化之前,人们经常忘记的一点就是,在进行的优化的时候我们需要初始化参数,keras提供了参数初始化类,我们在对一个网络进行优化的时候会使用到它,比如我们想进行正态分布的随机初始化:

from keras importinitializers

rn=initializers.RandomNormal(mean=0,stddev=1,seed=42)


我们设置好了一个均值为零,标准差为1。随机数种子为42的正态分布随机初始化器。我们在搭建网络中通过kernel_initializer参数传递初始化方法:

from keras importinitializers

from keras.models import Model
from keras.layers import Input,Dense,ReLU,softmax
rn=initializers.RandomNormal(mean=
0,stddev=1,seed=42)
inputs=Input(shape=(
100,))
x=Dense(
32,kernel_initializer=rn)(inputs)
y=ReLU()(x)
out=Dense(
10,kernel_initializer=rn)(y)
out=softmax()(out)
model=Model(inputs=inputs,outputs=out)


同时,我们需要知道损失函数、优化算法和评估标准,他们分别可以从以下代码获得:

from keras import losses

loss=losses.categorical_crossentropy


from keras importoptimizers
sgd=optimizers.SGD(lr=0.1,decay=1e-10,momentum=0.9,nesterov=True)


from keras import metrics
performance=metrics.categorical_accuracy


其中,我们指定损失函数的交叉熵,优化算法为带有nesterov动量的随机梯度下降,评估标准为准确率。就可以用损失函数、优化算法以及评估标准编译好我们的模型:

model.compile(loss=loss, optimizer=sgd,metrcis=[performance])


接下来我们使用模型的fit方法开始训练数据:

model.fit(x=X, y=y, batch_size=32, epochs=1,verbose=1)


其中X,y是我们的数据,特别需要注意的是,batch_size就是指每次用于梯度更新的样本数量,epochs是指整体数据被迭代的次数,与iteration不同,iteration是指进行的梯度更新的次数。verbose是一个显示日志的开关,如果设置为1,在训练过程中,会出现一个萌萌的进度条,不知道多少人因为这个可爱的进度条,陷入keras无法自拔。


训练完成后,我们可以方便的将keras模型保存为HDF5文件(需要安装python库:h5py):

model.save('duxinshu.h5')


就保存到了当前面文件夹,当我们在其他地方使用这个模型时,只需要:

from keras.model import load_model

model = load_model('my_model.h5')


除此之外,我们还可以将上述的模型打印出来,使用:

model.summary()


就可以在解释器中看到模型的状态,同时我们还可以安装ann_visualizer库,将模型可视化。


读芯君开扒


课堂TIPS


• 很多人都会认为keras作为一个容易上手的框架,是把很多运算隐藏,所以包装太多,灵活性一定很差。但是需要注意,keras使用了tensorflow、Theano和CNTK的backend,我们完全使用其后端来进行创新设计,灵活性事实上非常高,前提是一定要清楚深度学习和机器学习很多理论。


• keras的模型搭建方式有两种,本文介绍了其中一种,叫做函数式模型,另外一种叫做序列式,序列式搭建简单模型更快,但函数式更加灵活。此文仅展示了keras的基本功能,还有很多功能将在具体的任务中使用。


留言 点赞 发个朋友圈

我们一起探讨AI落地的最后一公里


作者:唐僧不用海飞丝


如需转载,请后台留言,遵守转载规范


推荐文章阅读


【周末AI课堂 | 第三十三讲】神经网络综观(理论篇)

【周末AI课堂 | 第三十二讲】从感知机到深度学习(代码篇)

【周末AI课堂 | 第三十一讲】从感知机到深度学习(理论篇)

【周末AI课堂 | 第三十讲】理解梯度下降(二)(代码篇)

【周末AI课堂 | 第二十九讲】理解梯度下降(二)(理论篇)

【周末AI课堂 | 第二十八讲】理解梯度下降(一)(代码篇)

【周末AI课堂 | 第二十七讲】理解梯度下降(一)(理论篇)

【周末AI课堂 | 第二十六讲】理解损失函数(代码篇)

【周末AI课堂 | 第二十五讲】理解损失函数(理论篇)

【周末AI课堂 | 第二十四讲】聚类的几个重要问题(代码篇)

【周末AI课堂 | 第二十三讲】聚类的几个重要问题(理论篇)

【周末AI课堂 | 第二十二讲】Boosting集成(代码篇)

【周末AI课堂 | 第二十一讲】Boosting集成(理论篇)

【周末AI课堂 | 第二十讲】bagging集成和stacking集成(代码篇)

【周末AI课堂 | 第十九讲】bagging集成和stacking集成(理论篇)

【周末AI课堂 | 第十八讲】非参模型进阶(代码篇)

【周末AI课堂 | 第十七讲】非参模型进阶(理论篇)

【周末AI课堂 | 第十六讲】非参模型初步(代码篇)

【周末AI课堂 | 第十五讲】非参模型初步(理论篇)

【周末AI课堂 | 第十四讲】基于贝叶斯推断的回归模型(代码篇)

【周末AI课堂 | 第十三讲】基于贝叶斯推断的回归模型(理论篇)

【周末AI课堂 | 第十二讲】基于贝叶斯推断的分类模型(代码篇)

【周末AI课堂 | 第十一讲】基于贝叶斯推断的分类模型(理论篇)

【周末AI课堂 | 第十讲】核技巧(代码篇)

【周末AI课堂 | 第九讲】核技巧(理论篇)

【周末AI课堂 | 第八讲】非线性降维方法(代码篇)

【周末AI课堂 | 第七讲】非线性降维方法(理论篇)

【周末AI课堂 | 第六讲】线性降维方法(代码篇)

【周末AI课堂 | 第五讲】线性降维方法(理论篇)

【周末AI课堂 | 第四讲】如何进行特征选择(代码篇)

【周末AI课堂 | 第三讲】如何进行特征选择(理论篇)

【周末AI课堂 | 第二讲】过拟合问题(代码篇)

【周末AI课堂 | 第一讲】过拟合问题(理论篇)


长按识别二维码可添加关注

读芯君爱你


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存